home *** CD-ROM | disk | FTP | other *** search
/ Programming a Multiplayer FPS in DirectX / Programming a Multiplayer FPS in DirectX (Companion CD).iso / DirectX / dxsdk_oct2004.exe / dxsdk.exe / Samples / C++ / DirectInput / DIConfig / useful.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2004-09-27  |  13.4 KB  |  634 lines

  1. //-----------------------------------------------------------------------------
  2. // File: useful.cpp
  3. //
  4. // Desc: Contains various utility classes and functions to help the
  5. //       UI carry its operations more easily.
  6. //
  7. // Copyright (C) Microsoft Corporation. All Rights Reserved.
  8. //-----------------------------------------------------------------------------
  9.  
  10. #include <windows.h>
  11. #include <tchar.h>
  12. #include <wchar.h>
  13. #include <stdio.h>
  14. #include <stdarg.h>
  15.  
  16. // assert include (make sure assert actually works with build)
  17. #ifdef DBG
  18. #undef NDEBUG
  19. #endif
  20. #include <assert.h>
  21.  
  22. #include "useful.h"
  23. #include "collections.h"
  24.  
  25.  
  26. /*--------- \/ stuff for collections.h \/ ---------*/
  27. BOOL AfxIsValidAddress( const void* lp, UINT nBytes, BOOL bReadWrite)
  28. {
  29. //    return lp != NULL;
  30.  
  31.     // simple version using Win-32 APIs for pointer validation.
  32.     return (lp != NULL && !IsBadReadPtr(lp, nBytes) &&
  33.         (!bReadWrite || !IsBadWritePtr((LPVOID)lp, nBytes)));
  34. }
  35.  
  36. CPlex* PASCAL CPlex::Create(CPlex*& pHead, UINT nMax, UINT cbElement)
  37. {
  38.     assert(nMax > 0 && cbElement > 0);
  39.     CPlex* p = (CPlex*) new BYTE[sizeof(CPlex) + nMax * cbElement];
  40.             // may throw exception
  41.     if (p)
  42.     {
  43.         p->pNext = pHead;
  44.         pHead = p;  // change head (adds in reverse order for simplicity)
  45.     }
  46.     return p;
  47. }
  48.  
  49. void CPlex::FreeDataChain()     // free this one and links
  50. {
  51.     CPlex* p = this;
  52.     while (p != NULL)
  53.     {
  54.         BYTE* bytes = (BYTE*) p;
  55.         CPlex* pNext = p->pNext;
  56.         delete[] bytes;
  57.         p = pNext;
  58.     }
  59. }
  60. /*--------- /\ stuff for collections.h /\ ---------*/
  61.  
  62.  
  63. int ConvertVal(int x, int a1, int a2, int b1, int b2)
  64. {
  65.     assert(a1 != a2 && a2 - a1);
  66.     return MulDiv(x - a1, b2 - b1, a2 - a1) + b1;
  67. }
  68.  
  69. double dConvertVal(double x, double a1, double a2, double b1, double b2)
  70. {
  71.     assert(a1 != a2 && a2 - a1);
  72.     return (x - a1) * (b2 - b1) / (a2 - a1) + b1;
  73. }
  74.  
  75. SIZE GetRectSize(const RECT &rect)
  76. {
  77.     SIZE size = {
  78.         rect.right - rect.left,
  79.         rect.bottom - rect.top};
  80.     return size;
  81. }
  82.  
  83. SIZE GetTextSize(LPCTSTR tszText, HFONT hFont)
  84. {
  85.     if (!tszText)
  86.     {
  87.         SIZE z = {0, 0};
  88.         return z;
  89.     }
  90.     RECT trect = {0, 0, 1, 1};
  91.     HDC hDC = CreateCompatibleDC(NULL);
  92.     if (hDC != NULL)
  93.     {
  94.         HGDIOBJ hOld = NULL;
  95.         if (hFont)
  96.             hOld = SelectObject(hDC, hFont);
  97.         DrawText(hDC, tszText, -1, &trect, DT_CALCRECT | DT_NOPREFIX);
  98.         if (hFont)
  99.             SelectObject(hDC, hOld);
  100.         DeleteDC(hDC);
  101.     }
  102.     SIZE size = {trect.right - trect.left, trect.bottom - trect.top};
  103.     return size;
  104. }
  105.  
  106. int GetTextHeight(HFONT hFont)
  107. {
  108.     static const TCHAR str[] = _T("Happy Test!  :D");
  109.     SIZE size = GetTextSize(str, hFont);
  110.     return size.cy;
  111. }
  112.  
  113. int vFormattedMsgBox(HINSTANCE hInstance, HWND hParent, UINT uType, UINT uTitle, UINT uMsg, va_list args)
  114. {
  115.     int i;
  116.     const int len = 1024;
  117.     static TCHAR title[len], format[len], msg[len];
  118.  
  119.     if (!LoadString(hInstance, uTitle, title, len))
  120.         _tcscpy(title, _T("(could not load title string)"));
  121.     
  122.     if (!LoadString(hInstance, uMsg, format, len))
  123.         return MessageBox(hParent, _T("(could not load message/format string)"), title, uType);
  124.  
  125. #ifdef WIN95
  126.     {
  127.         char *psz = NULL;
  128.         char szDfs[1024]={0};
  129.         strncpy(szDfs,format, 1024);                    // make a local copy of format string
  130.         while (psz = strstr(szDfs,"%p"))                // find each %p
  131.             *(psz+1) = 'x';                                // replace each %p with %x
  132.         i = _vsntprintf(msg, sizeof(msg)/sizeof(TCHAR), szDfs, args);            // use the local format string
  133.     }
  134. #else
  135.     {
  136.         i = _vsntprintf(msg, sizeof(msg)/sizeof(TCHAR), format, args);
  137.     }
  138. #endif
  139.     // _vsntprintf may not null-terminate the buffer if the count of characters it writes is equal to the buffer size;
  140.     // so null-terminate it just in case
  141.     msg[len-1] = 0;
  142.  
  143.     if (i < 0)
  144.         return MessageBox(hParent, _T("(could not format message)"), title, uType);
  145.  
  146.     if (i < 1)
  147.         msg[0] = 0;
  148.  
  149.     return MessageBox(hParent, msg, title, uType);
  150. }
  151.  
  152. int FormattedMsgBox(HINSTANCE hInstance, HWND hParent, UINT uType, UINT uTitle, UINT uMsg, ...)
  153. {
  154.     va_list args;
  155.     va_start(args, uMsg);
  156.     int i = vFormattedMsgBox(hInstance, hParent, uType, uTitle, uMsg, args);
  157.     va_end(args);
  158.     return i;
  159. }
  160.  
  161. BOOL UserConfirm(HINSTANCE hInstance, HWND hParent, UINT uTitle, UINT uMsg, ...)
  162. {
  163.     va_list args;
  164.     va_start(args, uMsg);
  165.     int i = vFormattedMsgBox(hInstance, hParent, MB_ICONQUESTION | MB_YESNO, uTitle, uMsg, args);
  166.     va_end(args);
  167.     return i == IDYES;
  168. }
  169.  
  170. int FormattedErrorBox(HINSTANCE hInstance, HWND hParent, UINT uTitle, UINT uMsg, ...)
  171. {
  172.     va_list args;
  173.     va_start(args, uMsg);
  174.     int i = vFormattedMsgBox(hInstance, hParent, MB_OK | MB_ICONSTOP, uTitle, uMsg, args);
  175.     va_end(args);
  176.     return i;
  177. }
  178.  
  179. int FormattedLastErrorBox(HINSTANCE hInstance, HWND hParent, UINT uTitle, UINT uMsg, DWORD dwError)
  180. {
  181.     // format an error message from GetLastError().
  182.     LPVOID lpMsgBuf = NULL;
  183.     DWORD result = FormatMessage(
  184.         FORMAT_MESSAGE_ALLOCATE_BUFFER |
  185.         FORMAT_MESSAGE_FROM_SYSTEM |
  186.         FORMAT_MESSAGE_IGNORE_INSERTS,
  187.         NULL,
  188.         dwError,
  189.         MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  190.         (LPTSTR) &lpMsgBuf,
  191.         0,
  192.         NULL);
  193.  
  194.     if (!result || lpMsgBuf == NULL)
  195.         return FormattedErrorBox(hInstance, hParent, uTitle, uMsg, 
  196.             _T("An unknown error occured (could not format the error code)."));
  197.  
  198.     int i = FormattedErrorBox(hInstance, hParent, uTitle, uMsg, (LPCTSTR)lpMsgBuf);
  199.  
  200.     LocalFree(lpMsgBuf);
  201.  
  202.     return i;
  203. }
  204.  
  205. LPTSTR AllocLPTSTR(LPCWSTR wstr)
  206. {
  207.     if (wstr == NULL)
  208.         return NULL;
  209.  
  210. #ifdef UNICODE
  211.     return _tcsdup(wstr);
  212. #else
  213.     int len = wcslen(wstr) * 2 + 1;
  214.     char *ret = (char *)malloc(len);
  215.     if (!ret)
  216.         return NULL;
  217.     WideCharToMultiByte(CP_ACP, 0, wstr, -1, ret, len, NULL, NULL);
  218.     ret[len-1] = '\0';
  219.     return ret;
  220. #endif
  221. }
  222.  
  223. LPTSTR AllocLPTSTR(LPCSTR str)
  224. {
  225.     if (str == NULL)
  226.         return NULL;
  227.  
  228. #ifndef UNICODE
  229.     return _tcsdup(str);
  230. #else
  231.     int len = strlen(str);
  232.     WCHAR *ret = (WCHAR *)malloc((len + 1) * sizeof(WCHAR));
  233.     if (!ret)
  234.         return NULL;
  235.     mbstowcs(ret, str, len);
  236.     ret[len] = L'\0';
  237.     return ret;
  238. #endif
  239. }
  240.  
  241. void CopyStr(LPWSTR dest, LPCWSTR src, size_t max)
  242. {
  243.     if (dest == NULL || src == NULL)
  244.         return;
  245.  
  246.     wcsncpy(dest, src, max);
  247. }
  248.  
  249. void CopyStr(LPSTR dest, LPCSTR src, size_t max)
  250. {
  251.     if (dest == NULL || src == NULL)
  252.         return;
  253.  
  254.     strncpy(dest, src, max);
  255. }
  256.  
  257. void CopyStr(LPWSTR dest, LPCSTR src, size_t max)
  258. {
  259.     if (dest == NULL || src == NULL)
  260.         return;
  261.  
  262.     mbstowcs(dest, src, max);
  263. }
  264.  
  265. void CopyStr(LPSTR dest, LPCWSTR src, size_t max)
  266. {
  267.     if (dest == NULL || src == NULL)
  268.         return;
  269.  
  270.     WideCharToMultiByte(CP_ACP, 0, src, -1, dest, max, NULL, NULL);
  271. }
  272.  
  273. LPWSTR AllocLPWSTR(LPCWSTR wstr)
  274. {
  275.     if (wstr == NULL)
  276.         return NULL;
  277.  
  278.     return _wcsdup(wstr);
  279. }
  280.  
  281. LPWSTR AllocLPWSTR(LPCSTR str)
  282. {
  283.     if (str == NULL)
  284.         return NULL;
  285.  
  286.     size_t len = strlen(str);
  287.     size_t retsize = mbstowcs(NULL, str, len);
  288.     WCHAR *ret = (WCHAR *)malloc((retsize + 1) * sizeof(WCHAR));
  289.     if (!ret)
  290.         return NULL;
  291.     mbstowcs(ret, str, len);
  292.     ret[retsize] = L'\0';
  293.     return ret;
  294. }
  295.  
  296. LPSTR AllocLPSTR(LPCWSTR wstr)
  297. {
  298.     if (wstr == NULL)
  299.         return NULL;
  300.  
  301.     size_t len = wcslen(wstr);
  302.     size_t retsize = WideCharToMultiByte(CP_ACP, 0, wstr, -1, NULL, 0, NULL, NULL);
  303.     CHAR *ret = (CHAR *)malloc((retsize + 1) * sizeof(CHAR));
  304.     if (!ret)
  305.         return NULL;
  306.     WideCharToMultiByte(CP_ACP, 0, wstr, -1, ret, retsize, NULL, NULL);
  307.     ret[retsize] = '\0';
  308.     return ret;
  309. }
  310.  
  311. LPSTR AllocLPSTR(LPCSTR str)
  312. {
  313.     if (str == NULL)
  314.         return NULL;
  315.  
  316.     return _strdup(str);
  317. }
  318.  
  319. LPTSTR AllocFileNameNoPath(LPTSTR path)
  320. {
  321.     TCHAR fname[_MAX_FNAME];
  322.     TCHAR ext[_MAX_EXT];
  323.  
  324.     if (path == NULL) return NULL;
  325.  
  326.     _tsplitpath(path, NULL, NULL, fname, ext);
  327.  
  328.     LPTSTR ret = (LPTSTR)malloc(sizeof(TCHAR) * (_tcslen(fname) + _tcslen(ext) + 1));
  329.     if (ret != NULL)
  330.     {
  331.         _tcscpy(ret, fname);
  332.         _tcscat(ret, ext);
  333.     }
  334.  
  335.     return ret;
  336. }
  337.  
  338. LPTSTR utilstr::Eject()
  339. {
  340.     LPTSTR str = m_str;
  341.     m_str = NULL;
  342.     m_len = 0;
  343.     return str;
  344. }
  345.  
  346. void utilstr::Empty()
  347. {
  348.     if (m_str != NULL)
  349.         free(m_str);
  350.     m_len = 0;
  351. }
  352.  
  353. bool utilstr::IsEmpty() const
  354. {
  355.     return !GetLength();
  356. }
  357.  
  358. int utilstr::GetLength() const
  359. {
  360.     if (m_str == NULL)
  361.         return 0;
  362.     if (!m_len)
  363.         return 0;
  364.  
  365.     return _tcslen(m_str);
  366. }
  367.  
  368. void utilstr::Format(LPCTSTR format, ...)
  369. {
  370.     static TCHAR buf[2048];
  371.     va_list args;
  372.     va_start(args, format);
  373. #ifdef WIN95
  374.     {
  375.         char *psz = NULL;
  376.         char szDfs[1024]={0};
  377.         strncpy(szDfs,format, 1024);  // make a local copy of format string
  378.         while (psz = strstr(szDfs,"%p"))  // find each %p
  379.             *(psz+1) = 'x';  // replace each %p with %x
  380.         _vsntprintf(buf, sizeof(buf)/sizeof(TCHAR), szDfs, args);  // use the local format string
  381.     }
  382. #else
  383.     {
  384.         _vsntprintf(buf, sizeof(buf)/sizeof(TCHAR), format, args);
  385.     }
  386. #endif
  387.     // _vsntprintf may not null-terminate the buffer if the count of characters it writes is equal to the buffer size
  388.     // so null-terminate it just in case
  389.     buf[2047] = 0;
  390.  
  391.     va_end(args);
  392.     equal(buf);
  393. }
  394.  
  395. void utilstr::equal(LPCTSTR str)
  396. {
  397.     Empty();
  398.     if (str == NULL)
  399.         return;
  400.     m_len = _tcslen(str);
  401.     m_str = (LPTSTR)malloc(sizeof(TCHAR) * (m_len + 1));
  402.     if (m_str != NULL)
  403.         _tcscpy(m_str, str);
  404.     else
  405.         m_len = 0;
  406. }
  407.  
  408. void utilstr::add(LPCTSTR str)
  409. {
  410.     if (str == NULL)
  411.         return;
  412.     if (IsEmpty())
  413.     {
  414.         equal(str);
  415.         return;
  416.     }
  417.     int len = _tcslen(str);
  418.     int newlen = m_len + len;
  419.     LPTSTR newstr = (LPTSTR)malloc(sizeof(TCHAR) * (newlen + 1));
  420.     if (newstr == NULL)
  421.         return;
  422.     _tcscpy(newstr, m_str);
  423.     _tcscat(newstr, str);
  424.     Empty();
  425.     m_str = newstr;
  426.     m_len = newlen;
  427. }
  428.  
  429. LPTSTR AllocFlagStr(DWORD value, const AFS_FLAG flag[], int flags)
  430. {
  431.     utilstr ret;    // return string
  432.     DWORD allknownbits = 0;  // check value to see if there are any bits
  433.                              // set for which we don't have a define
  434.  
  435.     // handle each flag
  436.     bool bflagfound = false;
  437.     for (int i = 0; i < flags; i++)
  438.     {
  439.         // set bit for this flag in allknownbits
  440.         allknownbits |= flag[i].value;
  441.  
  442.         // if this bit is set in the passed value, or the value
  443.         // is zero and we're on the zero flag,
  444.         // add the define for this bit/flag to the return string
  445.         if (value ? value & flag[i].value : !flag[i].value)
  446.         {
  447.             // adding binary or operators between flags
  448.             if (bflagfound)
  449.                 ret += _T(" | ");
  450.             ret += flag[i].name;
  451.             bflagfound = true;
  452.         }
  453.     }
  454.  
  455.     // now see if there are any unknown bits in passed flag
  456.     DWORD unknownbits = value & ~allknownbits;
  457.     if (unknownbits)
  458.     {
  459.         // add hex number for unknown bits
  460.         utilstr unk;
  461.         unk.Format(_T("0x%08X"), unknownbits);
  462.         if (bflagfound)
  463.             ret += _T(" | ");
  464.         ret += unk;
  465.     }
  466.  
  467.     // if value is zero (and no flags for zero) we should just set the string to "0"
  468.     if (!value && !bflagfound)
  469.         ret = _T("0");
  470.  
  471.     // now the string should definitely not be empty, in any case
  472.     assert(!ret.IsEmpty());
  473.  
  474.     // finally, add a comment that has hex number for entire value
  475.     // (for debugging)
  476.     utilstr temp;
  477.     temp.Format(_T(" /* 0x%08X */"), value);
  478.     ret += temp;
  479.  
  480.     // done
  481.     return ret.Eject();
  482. }
  483.  
  484. void PutLinePoint(HDC hDC, POINT p)
  485. {
  486.     MoveToEx(hDC, p.x, p.y, NULL);
  487.     LineTo(hDC, p.x + 1, p.y);
  488. }
  489.  
  490. void PolyLineArrowShadow(HDC hDC, POINT *p, int i)
  491. {
  492.     PolyLineArrow(hDC, p, i, TRUE);
  493. }
  494.  
  495. void PolyLineArrow(HDC hDC, POINT *rgpt, int nPoints, BOOL bDoShadow)
  496. {
  497.     int i;
  498.  
  499.     if (rgpt == NULL || nPoints < 1)
  500.         return;
  501.  
  502.     if (nPoints > 1)
  503.         for (i = 0; i < nPoints - 1; i++)
  504.         {
  505.             SPOINT a = rgpt[i], b = rgpt[i + 1];
  506.  
  507.             if (bDoShadow)
  508.             {
  509.                 int rise = abs(b.y - a.y), run = abs(b.x - a.x);
  510.                 bool vert = rise > run;
  511.                 int ord = vert ? 1 : 0;
  512.                 int nord = vert ? 0 : 1;
  513.                 
  514.                 for (int o = -1; o <= 1; o += 2)
  515.                 {
  516.                     SPOINT c(a), d(b);
  517.                     c.a[nord] += o;
  518.                     d.a[nord] += o;
  519.                     MoveToEx(hDC, c.x, c.y, NULL);
  520.                     LineTo(hDC, d.x, d.y);
  521.                 }
  522.  
  523.                 bool reverse = a.a[ord] > b.a[ord];
  524.                 SPOINT e(reverse ? b : a), f(reverse ? a : b);
  525.                 e.a[ord] -= 1;
  526.                 f.a[ord] += 1;
  527.                 PutLinePoint(hDC, e);
  528.                 PutLinePoint(hDC, f);
  529.             }
  530.             else
  531.             {
  532.                 MoveToEx(hDC, a.x, a.y, NULL);
  533.                 LineTo(hDC, b.x, b.y);
  534.             }
  535.         }
  536.  
  537.     POINT z = rgpt[nPoints - 1];
  538.  
  539.     if (bDoShadow)
  540.     {
  541.         POINT pt[5] = {
  542.             {z.x, z.y + 2},
  543.             {z.x + 2, z.y},
  544.             {z.x, z.y - 2},
  545.             {z.x - 2, z.y}, };
  546.         pt[4] = pt[0];
  547.         Polyline(hDC, pt, 5);
  548.     }
  549.     else
  550.     {
  551.         MoveToEx(hDC, z.x - 1, z.y, NULL);
  552.         LineTo(hDC, z.x + 2, z.y);
  553.         MoveToEx(hDC, z.x, z.y - 1, NULL);
  554.         LineTo(hDC, z.x, z.y + 2);
  555.     }
  556. }
  557.  
  558. BOOL bEq(BOOL a, BOOL b)
  559. {
  560.     bool c = !a, d = !b;
  561.     return (c == d) ? TRUE : FALSE;
  562. }
  563.  
  564. void DrawArrow(HDC hDC, const RECT &rect, BOOL bVert, BOOL bUpLeft)
  565. {
  566.     SRECT srect = rect;
  567.     srect.right--;
  568.     srect.bottom--;
  569.     int ord = bVert ? 1 : 0;
  570.     int nord = bVert ? 0 : 1;
  571.     SPOINT p(!bUpLeft ? srect.lr : srect.ul), b(!bUpLeft ? srect.ul : srect.lr);
  572.     b.a[ord] += bUpLeft ? -1 : 1;
  573.     SPOINT t = p;
  574.     t.a[nord] = (p.a[nord] + b.a[nord]) / 2;
  575.     SPOINT u;
  576.     u.a[ord] = b.a[ord];
  577.     u.a[nord] = p.a[nord];
  578.     POINT poly[] = { {t.x, t.y}, {u.x, u.y}, {b.x, b.y} };
  579.     Polygon(hDC, poly, 3);
  580. }
  581.  
  582. BOOL ScreenToClient(HWND hWnd, LPRECT rect)
  583. {
  584.     if (rect == NULL)
  585.         return FALSE;
  586.  
  587.     SRECT sr = *rect;
  588.  
  589.     if (ScreenToClient(hWnd, &sr.ul.p) &&
  590.         ScreenToClient(hWnd, &sr.lr.p))
  591.     {
  592.         *rect = sr;
  593.         return TRUE;
  594.     }
  595.  
  596.     return FALSE;
  597. }
  598.  
  599. BOOL ClientToScreen(HWND hWnd, LPRECT rect)
  600. {
  601.     if (rect == NULL)
  602.         return FALSE;
  603.  
  604.     SRECT sr = *rect;
  605.  
  606.     if (ClientToScreen(hWnd, &sr.ul.p) &&
  607.         ClientToScreen(hWnd, &sr.lr.p))
  608.     {
  609.         *rect = sr;
  610.         return TRUE;
  611.     }
  612.  
  613.     return FALSE;
  614. }
  615.  
  616. #define z ((L"\0")[0])
  617.  
  618. int StrLen(LPCWSTR s)
  619. {
  620.     if (s == NULL)
  621.         return 0;
  622.  
  623.     return wcslen(s);
  624. }
  625.  
  626. int StrLen(LPCSTR s)
  627. {
  628.     if (s == NULL)
  629.         return 0;
  630.  
  631.     return strlen(s);
  632. }
  633.  
  634.